package com.dokicam.colordepth;

import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.text.TextUtils;
import android.util.Log;

import com.hjimi.api.iminect.ImiDevice;
import com.hjimi.api.iminect.ImiFrameMode;
import com.hjimi.api.iminect.ImiFrameType;
import com.hjimi.api.iminect.ImiImageFrame;
import com.hjimi.api.iminect.Utils;
import com.scanLab.DecodeEngine;
import com.scanLab.ScanResult;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Date;


public class SimpleViewer extends Thread {

    private boolean mShouldRun = false;

    private ImiFrameType mFrameType;
    private GLPanel mGLPanel;
    private DecodePanel mDecodePanel;
    private ImiDevice mDevice;
    private ImiFrameMode mCurrentMode;


    //后台解码线程
    private HandlerThread mDecodeBackgroundThread;
    //后台发送解码的handler
    private Handler mDecodeBackgroundHandler;

    private boolean isDecoding;

    private ScanCallBack callBack;

    public SimpleViewer(ImiDevice device, ImiFrameType frameType) {
        mDevice = device;
        mFrameType = frameType;

        isDecoding = false;
        startBackgroundThread();
    }

    public synchronized void startBackgroundThread(){
        if(this.mDecodeBackgroundThread != null) {
            Log.e("DL", "The Decode thread already started!");
        } else {
            this.mDecodeBackgroundThread = new HandlerThread("DoDocodeBackground", 10);
            this.mDecodeBackgroundThread.start();
            this.mDecodeBackgroundHandler = new Handler(this.mDecodeBackgroundThread.getLooper());
        }

    }

    public void setGLPanel(GLPanel GLPanel) {
        this.mGLPanel = GLPanel;
    }

    public void setDecodePanel(DecodePanel decodePanel) {
        this.mDecodePanel = decodePanel;
    }

    @Override
    public void run() {
        super.run();

        //open stream.
        mDevice.openStream(mFrameType);

        //get current framemode.
        mCurrentMode = mDevice.getCurrentFrameMode(mFrameType);

        //start read frame.
        while (mShouldRun) {
            ImiImageFrame nextFrame = mDevice.readNextFrame(mFrameType, 25);

            //frame maybe null, if null, continue.
            if(nextFrame == null){
                continue;
            }

            switch (mFrameType)
            {
                case COLOR:
                    //draw color.
                    drawColor(nextFrame);
                    break;
                case DEPTH:
                    //draw depth.
                    drawDepth(nextFrame);
                    break;
            }
        }
    }




    /**
     * 解码后台线程
     */
    public class DecodingBackgroundRunnable implements Runnable {


        private byte[] bytes;
        DecodingBackgroundRunnable(byte[] bytes){
           this.bytes = bytes;
        }

        @Override
        public void run() {
                long t1 = System.currentTimeMillis();

                int width = 640;
                int height = 480;
                ScanResult data = DecodeEngine.startScan(bytes, width, height);
                long t2 = System.currentTimeMillis() - t1;
//            Debug.verbose("DL.doDecode", "It takes "+t2+" ms to decode!");
                //唤醒线程
                //判断解码结果

                if (data != null) {
//
                    if (callBack != null){
                        callBack.resultCallBack(data);
                    }
//                    previewFrameCallBack.receivedDecodedData(data);

                    //清空消息
                    mDecodeBackgroundHandler.removeCallbacksAndMessages(null);
                }else {
                    Log.e("DL.run", "data===" + data);
                }

                //清空消息
                mDecodeBackgroundHandler.removeCallbacksAndMessages(null);

                isDecoding = false;

        }
    }
    private void drawDepth(ImiImageFrame nextFrame) {
        ByteBuffer frameData = nextFrame.getData();
        int width = nextFrame.getWidth();
        int height = nextFrame.getHeight();


        byte[] bytes = new byte[frameData.remaining()];
        frameData.get(bytes, 0, bytes.length);


        //加入计算深度图
        if (!isDecoding){
            isDecoding = true;
            mDecodeBackgroundHandler.post(new DecodingBackgroundRunnable(bytes));
        }

        frameData = Utils.depth2RGB888(nextFrame, true, false);

        mGLPanel.paint(null, frameData, width, height);
    }

    private void drawColor(ImiImageFrame nextFrame) {
        ByteBuffer frameData = nextFrame.getData();
        int width = nextFrame.getWidth();
        int height = nextFrame.getHeight();


        //draw color image.
        switch (mCurrentMode.getFormat())
        {
            case IMI_PIXEL_FORMAT_IMAGE_H264:
                if(mDecodePanel != null){
                    mDecodePanel.paint(frameData, nextFrame.getTimeStamp());
                }
                break;
            case IMI_PIXEL_FORMAT_IMAGE_YUV420SP:
                frameData = Utils.yuv420sp2RGB(nextFrame);
                if(mGLPanel != null){
                    mGLPanel.paint(null, frameData, width, height);
                }
                break;
            case IMI_PIXEL_FORMAT_IMAGE_RGB24:
                if(mGLPanel != null){

                    mGLPanel.paint(null, frameData, width, height);
                }
                break;
            default:
                break;
        }
    }

    public void onPause(){
        if(mGLPanel != null){
            mGLPanel.onPause();
            isDecoding = false;
        }
    }

    public void onResume(){
        if(mGLPanel != null){
            mGLPanel.onResume();
            isDecoding = false;
        }
    }

    public void onStart(){
        if(!mShouldRun){
            mShouldRun = true;

            //start read thread
            this.start();
        }
    }

    public void onDestroy(){
        mShouldRun = false;

        //destroy stream.
        mDevice.closeStream(mFrameType);
        isDecoding = false;
    }


    public void setCallBack(ScanCallBack callBack){
            this.callBack = callBack;
    }

    private static void saveData(byte[] data, int width, int height){
        long ts = System.currentTimeMillis();

        try {
            File filePath = createImageFile();
            if (filePath == null || TextUtils.isEmpty(filePath.getAbsolutePath()))
                return;
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.sss");//设置日期格式
            String str = df.format(new Date());

            FileOutputStream fs = new FileOutputStream(String.format("%s/barcode_frame_%s.bmp"
                    , filePath, str));
            fs.write(data, 0, width * height);
            fs.flush();
            fs.close();


            ts = System.currentTimeMillis() - ts;
            Log.e("TAG", String.format("It takes %d milliseconds to save barcode.", ts));

        } catch (FileNotFoundException e) {
            Log.e("TAG","savePreviewData failed due to file not found.", e);
        } catch (IOException e) {
            Log.e("TAG", "savePreviewData failed due to unknown IO exception", e);
        }
    }


    private static File createImageFile(){
        File menu  = new File(getImageMenu());
        if (!menu.exists()){
            menu.mkdirs();
        }

        return menu;
    }

    private static String getImageMenu(){
        File sd = Environment.getExternalStorageDirectory();
        return String.format("%s/image",sd.getPath());
    }


    interface ScanCallBack{
        void resultCallBack(ScanResult result);
    }

}

